/*
 * Copyright (C) 2015 Qiujuer <qiujuer@live.cn>
 * WebSite http://www.qiujuer.net
 * Created 07/16/2015
 * Changed 08/11/2015
 * Version 3.0.0
 * Author Qiujuer
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.qiujuer.genius.ui.drawable;

import ohos.agp.components.Component;
import ohos.agp.components.element.StateElement;
import ohos.agp.render.BlendMode;
import ohos.agp.render.Canvas;
import ohos.agp.render.ColorFilter;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.media.image.common.PixelFormat;

import net.qiujuer.genius.ui.Ui;

/**
 * <p>
 * Subclasses should implement {@link #draw(Canvas, Paint)}
 * </p>
 */
public abstract class StatePaintDrawable extends StateColorDrawable implements Component.DrawTask {
    private ColorFilter mTintFilter;
    private StateElement mTint = null;
    private BlendMode mTintMode = BlendMode.SRC_IN;
    protected final Paint mPaint;
    Callback mCallback;

    public static interface Callback {
        public void invalidate();
    }

    /**
     * Initializes local dynamic properties from state. This should be called
     * after significant state changes, e.g. from the One True Constructor and
     * after inflating or applying a theme.
     *
     * @param
     */
    public StatePaintDrawable(int color) {
        super(color);
        mPaint = new Paint();
        mPaint.setColor(new Color(getColor()));
        mTintFilter = updateTintFilter(mTintFilter, mTint, mTintMode);
    }

    /**
     * setColorFilter
     *
     * @param cf ColorFilter
     */
    public void setColorFilter(ColorFilter cf) {
        final Paint paint = mPaint;
        if (paint != null && paint.getColorFilter() != cf) {
            paint.setColorFilter(cf);
            invalidateSelf();
        }
    }

    /**
     * getOpacity
     *
     * @return iny
     */
    public int getOpacity() {
        final Paint p = mPaint;
        if (p.getBlendMode() == null) {
            final int alpha = (int) p.getAlpha();
            if (alpha == 0) {
                return PixelFormat.ARGB_8888.getValue();
            }
            if (alpha == 255) {
                return PixelFormat.ARGB_8888.getValue();
            }
        }
        // not sure, so be safe
        return PixelFormat.ARGB_8888.getValue();
    }

    public void setDither(boolean dither) {
        mPaint.setDither(dither);
        invalidateSelf();
    }

    public void setTintList(StateElement tint) {
        if (mTint != tint) {
            mTint = tint;
            mTintFilter = updateTintFilter(mTintFilter, tint, mTintMode);
            invalidateSelf();
        }
    }

    public void setTintMode(BlendMode tintMode) {
        if (tintMode != mTintMode || tintMode.compareTo(mTintMode) != 0) {
            mTintMode = tintMode;
            mTintFilter = updateTintFilter(mTintFilter, mTint, tintMode);
            invalidateSelf();
        }
    }

    @Override
    public boolean isStateful() {
        return super.isStateful() || (mTint != null && mTint.isStateful());
    }

    @Override
    protected boolean onStateChange(int[] stateSet) {
        boolean changed = super.onStateChange(stateSet);
        if (mTint != null && mTintMode != null) {
            mTintFilter = updateTintFilter(mTintFilter, mTint, mTintMode);
            return true;
        }
        return changed;
    }

    @Override
    protected void onColorChange(int color) {
        final Paint paint = mPaint;
        if (paint != null && paint.getColor().getValue() != color)
            paint.setColor(new Color(color));
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        drawToCanvas(canvas);
    }

    @Override
    public void drawToCanvas(Canvas canvas) {

        super.drawToCanvas(canvas);
        final Paint paint = mPaint;
        final int prevAlpha = (int) paint.getAlpha();
        paint.setAlpha(Ui.modulateAlpha(prevAlpha, getAlpha()));
        // only draw shape if it may affect output
        final boolean clearColorFilter;
        if (mTintFilter != null && paint.getColorFilter() == null) {
            paint.setColorFilter(mTintFilter);
            clearColorFilter = true;
        } else {
            clearColorFilter = false;
        }
        // call draw
        draw(canvas, mPaint);
        if (clearColorFilter) {
            paint.setColorFilter(null);
        }
        // restore
        paint.setAlpha(prevAlpha);
    }

    /**
     * Returns the Paint used to draw the shape.
     *
     * @return mPaint
     */
    public Paint getPaint() {
        return mPaint;
    }

    /**
     * Subclasses should implement this method to do the actual drawing
     *
     * @param canvas The current {@link Canvas} to draw into
     * @param paint The {@link Paint} the Paint object that defines with the current
     * color
     */
    public abstract void draw(Canvas canvas, Paint paint);


    // other subclass could wack the Shader's localmatrix based on the
    // resize params (e.g. scaletofit, etc.). This could be used to scale
    // a bitmap to fill the bounds without needing any other special casing.

    /**
     * Ensures the tint filter is consistent with the current tint color and
     * mode.
     *
     * @param tintFilter tintFilter
     * @param tint tint
     * @param tintMode tintMode
     * @return ColorFilter
     */
    ColorFilter updateTintFilter(ColorFilter tintFilter, StateElement tint,
                                 BlendMode tintMode) {
//        if (tint == null || tintMode == null) {
//            return null;
//        }
//
//        //final int color = tint.getColorForState(getState(), Color.TRANSPARENT);
//       /* if (tintFilter == null) {
//            return new ColorFilter(color, tintMode);
//        }*/
//
//        //tintFilter.setColor(color);
//        //tintFilter.setMode(tintMode);
//        try {
//            //noinspection unchecked
//            Class<ColorFilter> tClass = (Class<ColorFilter>) tintFilter.getClass();
//            Method method = tClass.getMethod("setColor", Integer.class);
//            method.invoke(tintFilter, color);
//
//            method = tClass.getMethod("setMode", BlendMode.class);
//            method.invoke(tintFilter, tintMode);
//            return tintFilter;
//        } catch (Exception e) {
//            return new ColorFilter(color, tintMode);
//        }
        return null;
    }

    /**
     * 設置回調
     *
     * @param mCallback 回調
     */
    public void setMCallback(Callback mCallback) {
        this.mCallback = mCallback;
    }

    public void invalidateSelf() {
        System.out.println("=======55555=======");
        mCallback.invalidate();
    }
}
